/*
* `gnu.iou.dom'
* Copyright (C) 2006 John Pritchard.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package gnu.iou.dom.impl;
/**
* <p> DOM writers for XML UTF-8 format. </p>
*
* @see Formatter$Buffer
* @see Formatter$Stream
* @see Formatter$Null
*
* @author jdp
*/
public abstract class Formatter
{
/**
* Default indent character is space.
*/
public static char CHAR_INDENT = ' ';
/**
* Simple DOM writing stack used by DOM writers implements DOM
* walking with {@link gnu.iou.dom.Formatter$WriteX} semantics.
*/
public static class State
extends java.lang.Object
implements gnu.iou.dom.Formatter.State
{
private final static int DEPTH = 9;
private final static java.lang.String PR_NIL = "";
private int sp = 0;
private gnu.iou.dom.Element[] stack = new gnu.iou.dom.Element[DEPTH];
private boolean headline = true;
public State(){
super();
}
public void reset(){
this.sp = 0;
this.stack = new gnu.iou.dom.Element[DEPTH];
this.headline = true;
}
public void destroy(){
this.sp = 0;
this.stack = null;
this.headline = true;
}
public boolean headline(){
if (0 == this.sp)
return (this.headline = (!this.headline));
else
throw new gnu.iou.dom.Error.State("State is not <init>, indent is not zero.");
}
public int indent(){
return this.sp;
}
protected void push(gnu.iou.dom.Element elem){
if (null == elem)
throw new gnu.iou.dom.Error.State();
else {
this.stack[this.sp++] = elem;
if (this.sp >= this.stack.length){
gnu.iou.dom.Element[] copier = new gnu.iou.dom.Element[this.stack.length+DEPTH];
java.lang.System.arraycopy(this.stack,0,copier,0,this.stack.length);
this.stack = copier;
}
}
}
protected gnu.iou.dom.Element pop(){
if (-1 < this.sp){
this.sp -= 1;
gnu.iou.dom.Element re = this.stack[this.sp];
this.stack[this.sp] = null;
return re;
}
else
return null;
}
protected gnu.iou.dom.Element peek(){
return this.stack[this.sp];
}
protected void headline(gnu.iou.dom.Formatter out)
throws java.io.IOException
{
if (this.headline){
out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
this.headline = false;
}
}
/**
* @param map Optional XMLNS logic store used by this function
* to avoid duplication in output, managed by the caller to be
* specific to a scope. Forms a part of the whole XMLNS
* process.
* @param prefix QName prefix for namespace
* @param ns Namespace URI
* @param out Required target output
*/
protected void xmlns(gnu.iou.objmap map, String prefix, String ns, gnu.iou.dom.Formatter out)
throws java.io.IOException
{
if (null != ns && 0 < ns.length() &&
(null == map || null == map.get(prefix)))
{
if (null == prefix || 1 > prefix.length())
prefix = PR_NIL;
if (null != map){
if (null != map.get(prefix))
return;
else
map.put(prefix,ns);
}
out.print(' ');
if (PR_NIL != prefix){
out.print("xmlns:");
out.print(prefix);
out.print('=');
}
else
out.print("xmlns=");
//
out.printSafeQuoted(ns);
}
}
public boolean write(org.w3c.dom.Node node, gnu.iou.dom.Formatter out)
throws java.io.IOException
{
if (node instanceof gnu.iou.dom.Node)
return this.write( (gnu.iou.dom.Node)node, out);
else
throw new gnu.iou.dom.Error.Argument();
}
public boolean write(org.w3c.dom.CDATASection node, gnu.iou.dom.Formatter out)
throws java.io.IOException
{
return this.write( (gnu.iou.dom.CDATASection)node, out);
}
public boolean write(org.w3c.dom.Comment node, gnu.iou.dom.Formatter out)
throws java.io.IOException
{
return this.write( (gnu.iou.dom.Comment)node, out);
}
public boolean write(org.w3c.dom.Document node, gnu.iou.dom.Formatter out)
throws java.io.IOException
{
return this.write( (gnu.iou.dom.Document)node, out);
}
public boolean write(org.w3c.dom.Element node, gnu.iou.dom.Formatter out)
throws java.io.IOException
{
return this.write( (gnu.iou.dom.Element)node, out);
}
public boolean write(org.w3c.dom.Entity node, gnu.iou.dom.Formatter out)
throws java.io.IOException
{
throw new java.lang.UnsupportedOperationException("todo");
}
public boolean write(org.w3c.dom.EntityReference node, gnu.iou.dom.Formatter out)
throws java.io.IOException
{
throw new java.lang.UnsupportedOperationException("todo");
}
public boolean write(org.w3c.dom.ProcessingInstruction node, gnu.iou.dom.Formatter out)
throws java.io.IOException
{
throw new java.lang.UnsupportedOperationException("todo");
}
public boolean write(org.w3c.dom.Text node, gnu.iou.dom.Formatter out)
throws java.io.IOException
{
return this.write( (gnu.iou.dom.Text)node, out);
}
public boolean write(gnu.iou.dom.Node node, gnu.iou.dom.Formatter out)
throws java.io.IOException
{
if (null == node)
return false;
else {
switch (node.getNodeType()){
case org.w3c.dom.Node.CDATA_SECTION_NODE:
return this.write( (gnu.iou.dom.CDATASection)node, out);
case org.w3c.dom.Node.COMMENT_NODE:
return this.write( (gnu.iou.dom.Comment)node, out);
case org.w3c.dom.Node.DOCUMENT_NODE:
return this.write( (gnu.iou.dom.Document)node, out);
case org.w3c.dom.Node.ELEMENT_NODE:
return this.write( (gnu.iou.dom.Element)node, out);
case org.w3c.dom.Node.ENTITY_NODE:
return this.write( (gnu.iou.dom.Entity)node, out);
case org.w3c.dom.Node.ENTITY_REFERENCE_NODE:
return this.write( (gnu.iou.dom.EntityReference)node, out);
case org.w3c.dom.Node.PROCESSING_INSTRUCTION_NODE:
return this.write( (gnu.iou.dom.ProcessingInstruction)node, out);
case org.w3c.dom.Node.TEXT_NODE:
return this.write( (gnu.iou.dom.Text)node, out);
default:
throw new gnu.iou.dom.Error.Argument(node.getClass()+" type "+node.getNodeType());
}
}
}
public boolean write(gnu.iou.dom.CDATASection node, gnu.iou.dom.Formatter out)
throws java.io.IOException
{
out.print("<![CDATA[");
out.print(node.getNodeValue());
out.print("]]>");
return false;
}
public boolean write(gnu.iou.dom.Comment node, gnu.iou.dom.Formatter out)
throws java.io.IOException
{
out.print("<!-- ");
out.print(node.getNodeValue());
out.print(" -->");
return false;
}
public boolean write(gnu.iou.dom.Document node, gnu.iou.dom.Formatter out)
throws java.io.IOException
{
if (node.hasChildNodes()){
gnu.iou.dom.NodeList children = node.getChildNodes2();
gnu.iou.dom.Node child;
boolean re = false;
for (int idx = 0, len = children.getLength(); idx < len; idx++){
child = children.item2(idx);
re = this.write(child,out);
}
return re;
}
else
return false;
}
public boolean write(gnu.iou.dom.Element elem, gnu.iou.dom.Formatter out)
throws java.io.IOException
{
int indent = this.sp;
if (0 == indent)
this.headline(out);
//
gnu.iou.dom.Name name = elem.getNodeName2();
String qname = name.getQname();
//
gnu.iou.dom.Formatter.WriteX xelem = null;
/*
* Write head
*/
if (elem instanceof gnu.iou.dom.Formatter.WriteX){
xelem = (gnu.iou.dom.Formatter.WriteX)elem;
if (!xelem.writeX(out))
return true;/*(heuristic assumption)
*/
}
else {
if (elem instanceof gnu.iou.dom.Formatter.Prewrite){
gnu.iou.dom.Formatter.Prewrite prewrite = (gnu.iou.dom.Formatter.Prewrite)elem;
prewrite.prewrite(this);
}
out.print(indent,'<');
out.print(qname);
//
gnu.iou.objmap nstore = new gnu.iou.objmap();
String ns = name.getNamespace();
if ( null != ns && (!elem.isDeclaredNamespace(ns))){
//
String prefix = name.getPrefix();
this.xmlns(nstore,prefix,ns,out);
}
//
if (elem.hasAttributes()){
org.w3c.dom.NamedNodeMap attributes = elem.getAttributes();
org.w3c.dom.Node attribute;
String qn, value, pr;
for (int cc = 0, len = attributes.getLength(); cc < len; cc++){
attribute = attributes.item(cc);
value = attribute.getNodeValue();
qn = attribute.getNodeName();
if (qn != attribute.getLocalName()){
pr = attribute.getPrefix();
if (null != pr){
if ("xmlns".equals(pr)){
this.xmlns(nstore,attribute.getLocalName(),value,out);
continue;
}
else {
ns = attribute.getNamespaceURI();
if ( null != ns && (!elem.isDeclaredNamespace(ns)))
this.xmlns(nstore,pr,ns,out);
}
}
}
if ("xmlns".equals(qn))
continue;
else {
out.print(' ');
out.print(qn);
out.print('=');
out.printSafeQuoted(value);
}
}
}
}
/*
* Write body
*/
if (elem.hasChildNodes()){
gnu.iou.dom.NodeList children = elem.getChildNodes2();
boolean printline = (org.w3c.dom.Node.ELEMENT_NODE == children.typeFirst());
if (null == xelem){
if (printline)
out.println('>');
else
out.print('>');
}
this.push(elem);
org.w3c.dom.Node child;
for (int cc = 0, len = children.getLength(); cc < len; cc++){
child = children.item(cc);
printline = this.write(child,out);
}
if (elem != this.pop())
throw new gnu.iou.dom.Error.State("bug");
else {
/*
* Write tail with children
*/
if (null != xelem){
if (xelem instanceof gnu.iou.dom.Formatter.WriteX.Closing){
gnu.iou.dom.Formatter.WriteX.Closing closing =
(gnu.iou.dom.Formatter.WriteX.Closing)xelem;
return closing.writeX2(out);
}
else
return true;/*(heuristic assumption)
*/
}
else {
if (printline)
out.print(indent,"</");
else
out.print("</");
out.print(qname);
out.println('>');
if (elem instanceof gnu.iou.dom.Formatter.Postwrite){
gnu.iou.dom.Formatter.Postwrite postwrite = (gnu.iou.dom.Formatter.Postwrite)elem;
postwrite.postwrite(this);
}
return true;
}
}
}
else {
/*
* Write tail, no children
*/
if (null == xelem){
out.println("/>");
if (elem instanceof gnu.iou.dom.Formatter.Postwrite){
gnu.iou.dom.Formatter.Postwrite postwrite = (gnu.iou.dom.Formatter.Postwrite)elem;
postwrite.postwrite(this);
}
return true;
}
else
return true;/*(heuristic assumption)
*/
}
}
public boolean write(gnu.iou.dom.Entity node, gnu.iou.dom.Formatter out)
throws java.io.IOException
{
throw new java.lang.UnsupportedOperationException("todo");
}
public boolean write(gnu.iou.dom.EntityReference node, gnu.iou.dom.Formatter out)
throws java.io.IOException
{
throw new java.lang.UnsupportedOperationException("todo");
}
public boolean write(gnu.iou.dom.ProcessingInstruction node, gnu.iou.dom.Formatter out)
throws java.io.IOException
{
throw new java.lang.UnsupportedOperationException("todo");
}
public boolean write(gnu.iou.dom.Text node, gnu.iou.dom.Formatter out)
throws java.io.IOException
{
java.lang.String string = node.getNodeValue();
if (null != string){
int string_len = string.length();
if (0 < string_len){
out.printSafe(string);
switch (string.charAt(string_len-1)){
case '\r':
case '\n':
return true;
default:
return false;
}
}
}
return false;
}
}
/**
* Write DOM to XML in UTF-8 to buffer.
*/
public static class Buffer
extends gnu.iou.bbod
implements gnu.iou.dom.Formatter
{
private char char_indent = CHAR_INDENT;
private gnu.iou.dom.Formatter.State walker;
public Buffer(int cap){
super(cap);
this.walker = this.ctorState();
}
public Buffer(){
super();
this.walker = this.ctorState();
}
public Buffer(gnu.iou.bbuf buf){
super(buf);
this.walker = this.ctorState();
}
protected gnu.iou.dom.Formatter.State ctorState(){
return new Formatter.State();
}
protected final gnu.iou.dom.Formatter.State getState(){
return this.walker;
}
public void reset(){
this.walker.reset();
super.reset();
}
public int indent(){
return this.walker.indent();
}
public char getCharIndent(){
return this.char_indent;
}
public void setCharIndent(char ch){
if (0 == this.indent())
this.char_indent = ch; /*(liberal acceptance)
*/
else
throw new gnu.iou.dom.Error.State("State is not <init>, indent is not zero.");
}
public boolean headline(){
return this.walker.headline();
}
public void write(gnu.iou.dom.Element node)
throws java.io.IOException
{
if (null != node)
this.walker.write(node,this);
}
public void write(org.w3c.dom.Element node)
throws java.io.IOException
{
if (null != node)
this.walker.write(node,this);
}
public void write(gnu.iou.dom.Document node)
throws java.io.IOException
{
if (null != node)
this.walker.write(node,this);
}
public void write(org.w3c.dom.Document node)
throws java.io.IOException
{
if (null != node)
this.walker.write(node,this);
}
public void print(int indent, String string)
throws java.io.IOException
{
this.nprint(this.char_indent,indent);
this.print(string);
}
public void print(int indent, char ch)
throws java.io.IOException
{
this.nprint(this.char_indent,indent);
this.print(ch);
}
public void println(int indent, String string)
throws java.io.IOException
{
this.nprint(this.char_indent,indent);
this.println(string);
}
/**
* XML safe string encodes XML format special characters
* "&, <, >" to their XML 1.0 standard character
* references.
*/
public void printSafe(java.lang.String string)
throws java.io.IOException
{
if (null != string){
char cary[] = string.toCharArray(), ch;
for (int cc = 0, len = cary.length; cc < len; cc++){
ch = cary[cc];
switch(ch){
case '<':
this.print("<");
break;
case '>':
this.print(">");
break;
case '&':
this.print("&");
break;
default:
this.print(ch);
break;
}
}
}
}
/**
* XML safe string quoted in double quotes with quoted quotes
* using backslash.
*/
public void printSafeQuoted(java.lang.String string)
throws java.io.IOException
{
if (null != string){
this.print('"');
char cary[] = string.toCharArray(), ch;
for (int cc = 0, len = cary.length; cc < len; cc++){
ch = cary[cc];
switch(ch){
case '"':
this.print('\\');
this.print(ch);
break;
case '<':
this.print("<");
break;
case '>':
this.print(">");
break;
case '&':
this.print("&");
break;
default:
this.print(ch);
break;
}
}
this.print('"');
}
else
this.print("\"\"");
}
/**
* Destroy walker ({@link Formatter$State}) and close buffer.
*/
public void close()
throws java.io.IOException
{
this.walker.destroy();
super.close();
}
}
/**
* Write DOM to XML in UTF-8 to stream.
*/
public static class Stream
extends java.io.FilterOutputStream
implements gnu.iou.dom.Formatter
{
private final static char[] CRLF_CHAR = {
'\r',
'\n'
};
private final static byte[] CRLF_BYTE = {
(byte)'\r',
(byte)'\n'
};
private char char_indent = CHAR_INDENT;
private gnu.iou.dom.Formatter.State walker;
private boolean printline;
public Stream(java.io.OutputStream out){
super(out);
this.walker = this.ctorState();
}
protected gnu.iou.dom.Formatter.State ctorState(){
return new Formatter.State();
}
protected final gnu.iou.dom.Formatter.State getState(){
return this.walker;
}
public int indent(){
return this.walker.indent();
}
public char getCharIndent(){
return this.char_indent;
}
public void setCharIndent(char ch){
if (0 == this.indent())
this.char_indent = ch; /*(liberal acceptance)
*/
else
throw new gnu.iou.dom.Error.State("State is not <init>, indent is not zero.");
}
public boolean headline(){
return this.walker.headline();
}
public void write(gnu.iou.dom.Element node)
throws java.io.IOException
{
if (null != node)
this.walker.write(node,this);
}
public void write(org.w3c.dom.Element node)
throws java.io.IOException
{
if (null != node)
this.walker.write(node,this);
}
public void write(gnu.iou.dom.Document node)
throws java.io.IOException
{
if (null != node)
this.walker.write(node,this);
}
public void write(org.w3c.dom.Document node)
throws java.io.IOException
{
if (null != node)
this.walker.write(node,this);
}
public void print(char ch)
throws java.io.IOException
{
if (ch < 0x80)
this.write(ch);
else {
char[] cary = new char[]{ch};
byte[] bary = gnu.iou.utf8.encode(cary);
this.write(bary,0,bary.length);
}
}
public void nprint(char ch, int many)
throws java.io.IOException
{
if (1 > many)
return;
else if (ch < 0x80){
for (int cc = 0; cc < many; cc++)
this.write(ch);
}
else {
char[] cary = new char[]{ch};
byte[] bary = gnu.iou.utf8.encode(cary);
for (int cc = 0; cc < many; cc++)
this.write(bary,0,bary.length);
}
}
public void print(String string)
throws java.io.IOException
{
if (null != string){
char[] cary = string.toCharArray();
if (0 < cary.length){
byte[] bary = gnu.iou.utf8.encode(cary);
this.write(bary,0,bary.length);
}
}
}
public void print(int indent, String string)
throws java.io.IOException
{
this.nprint(this.char_indent,indent);
this.print(string);
}
public void print(int indent, char ch)
throws java.io.IOException
{
this.nprint(this.char_indent,indent);
this.print(ch);
}
public void println(char ch)
throws java.io.IOException
{
char[] cary = gnu.iou.chbuf.cat(ch,CRLF_CHAR);
byte[] bary = gnu.iou.utf8.encode(cary);
this.write(bary,0,bary.length);
}
public void println()
throws java.io.IOException
{
this.write(CRLF_BYTE,0,2);
}
public void println(String string)
throws java.io.IOException
{
char[] cary = null;
if (null != string)
cary = string.toCharArray();
cary = gnu.iou.chbuf.cat(cary,CRLF_CHAR);
byte[] bary = gnu.iou.utf8.encode(cary);
this.write(bary,0,bary.length);
}
public void println(int indent, String string)
throws java.io.IOException
{
this.nprint(this.char_indent,indent);
this.println(string);
}
/**
* XML safe string encodes XML format special characters
* "&, <, >" to their XML 1.0 standard character
* references.
*/
public void printSafe(java.lang.String string)
throws java.io.IOException
{
if (null != string){
char cary[] = string.toCharArray(), ch;
for (int cc = 0, len = cary.length; cc < len; cc++){
ch = cary[cc];
switch(ch){
case '<':
this.print("<");
break;
case '>':
this.print(">");
break;
case '&':
this.print("&");
break;
default:
this.print(ch);
break;
}
}
}
}
/**
* XML safe string quoted in double quotes with quoted quotes
* using backslash.
*/
public void printSafeQuoted(java.lang.String string)
throws java.io.IOException
{
if (null != string){
this.print('"');
char cary[] = string.toCharArray(), ch;
for (int cc = 0, len = cary.length; cc < len; cc++){
ch = cary[cc];
switch(ch){
case '"':
this.print('\\');
this.print(ch);
break;
case '<':
this.print("<");
break;
case '>':
this.print(">");
break;
case '&':
this.print("&");
break;
default:
this.print(ch);
break;
}
}
this.print('"');
}
else
this.print("\"\"");
}
/**
* Destroy walker ({@link Formatter$State}) and close stream.
*/
public void close()
throws java.io.IOException
{
this.walker.destroy();
super.close();
}
}
/**
* Null formatter evaluates output like others, but output goes
* nowhere.
*/
public static class Null
extends gnu.iou.dom.impl.Formatter
implements gnu.iou.dom.Formatter
{
private gnu.iou.dom.Formatter.State walker;
private char char_indent = CHAR_INDENT;
public Null(){
super();
this.walker = this.ctorState();
}
protected gnu.iou.dom.Formatter.State ctorState(){
return new Formatter.State();
}
protected final gnu.iou.dom.Formatter.State getState(){
return this.walker;
}
/**
* @return Current indent
*/
public int indent(){
return this.walker.indent();
}
public char getCharIndent(){
return this.char_indent;
}
public void setCharIndent(char ch){
if (0 == this.indent())
this.char_indent = ch; /*(liberal acceptance)
*/
else
throw new gnu.iou.dom.Error.State("State is not <init>, indent is not zero.");
}
/**
* @return Toggle headline
*/
public boolean headline(){
return this.walker.headline();
}
/**
* NOP
*/
public void write(int ch)
throws java.io.IOException
{}
/**
* NOP
*/
public void write(byte[] bary, int ofs, int len)
throws java.io.IOException
{}
/**
* Walk element
*/
public void write(gnu.iou.dom.Element node)
throws java.io.IOException
{
if (null != node)
this.walker.write(node,this);
}
/**
* Walk element
*/
public void write(org.w3c.dom.Element node)
throws java.io.IOException
{
if (null != node)
this.walker.write(node,this);
}
/**
* Walk document
*/
public void write(gnu.iou.dom.Document node)
throws java.io.IOException
{
if (null != node)
this.walker.write(node,this);
}
/**
* Walk document
*/
public void write(org.w3c.dom.Document node)
throws java.io.IOException
{
if (null != node)
this.walker.write(node,this);
}
/**
* NOP
*/
public void print(char ch)
throws java.io.IOException
{}
/**
* NOP
*/
public void nprint(char ch, int many)
throws java.io.IOException
{}
/**
* NOP
*/
public void print(String string)
throws java.io.IOException
{}
/**
* NOP
*/
public void print(int indent, String string)
throws java.io.IOException
{}
/**
* NOP
*/
public void print(int indent, char ch)
throws java.io.IOException
{}
/**
* NOP
*/
public void println(char ch)
throws java.io.IOException
{}
/**
* NOP
*/
public void println()
throws java.io.IOException
{}
/**
* NOP
*/
public void println(String string)
throws java.io.IOException
{}
/**
* NOP
*/
public void println(int indent, String string)
throws java.io.IOException
{}
/**
* NOP
*/
public void printSafe(java.lang.String string)
throws java.io.IOException
{}
/**
* NOP
*/
public void printSafeQuoted(java.lang.String string)
throws java.io.IOException
{}
/**
* NOP
*/
public void flush()
throws java.io.IOException
{}
/**
* Destroy walker ({@link Formatter$State}).
*/
public void close()
throws java.io.IOException
{
this.walker.destroy();
}
}
}